from rest_framework.exceptions import APIException
import re
from django.db import DataError
from rest_framework.validators import UniqueValidator


class CustomValidationError(APIException):
    """
    继承并重写验证器返回的结果,避免暴露字段
    """
    def __init__(self, detail, code=None):
        if code is None:
            code = 'manually'
        super().__init__(detail, code)


def qs_exists(queryset):
    try:
        return queryset.exists()
    except (TypeError, ValueError, DataError):
        return False


def qs_filter(queryset, **kwargs):
    try:
        return queryset.filter(**kwargs)
    except (TypeError, ValueError, DataError):
        return queryset.none()


class UniqueSerializerValidator(UniqueValidator):
    """
    唯一验证
    """
    message = '字段必须唯一'

    def filter_queryset(self, value, queryset, field_name):
        """
        Filter the queryset to all instances matching the given attribute.
        """
        filter_kwargs = {'%s__%s' % (field_name, self.lookup): value}
        return qs_filter(queryset, **filter_kwargs)

    def exclude_current_instance(self, queryset, instance):
        """
        If an instance is being updated, then do not include
        that instance itself as a uniqueness conflict.
        """
        if instance is not None:
            return queryset.exclude(pk=instance.pk)
        return queryset

    def __call__(self, value, serializer_field):
        # Determine the underlying model field name. This may not be the
        # same as the serializer field name if `source=<>` is set.
        field_name = serializer_field.source_attrs[-1]
        # Determine the existing instance, if this is an update operation.
        instance = getattr(serializer_field.parent, 'instance', None)

        queryset = self.queryset
        queryset = self.filter_queryset(value, queryset, field_name)
        queryset = self.exclude_current_instance(queryset, instance)
        if qs_exists(queryset):
            raise CustomValidationError(self.message)


class FileSerializerValidator:
    """
    文件类型和文件大小验证

    2.5MB – 2621440
    5MB – 5242880
    10MB – 10485760
    20MB – 20971520
    50MB – 5242880
    100MB 104857600
    250MB – 214958080
    500MB – 429916160
    """

    def __init__(self, extension=None, max_upload_size=None):
        if extension is None:
            extension = []
        self.extension = extension
        self.max_upload_size = max_upload_size

    def __call__(self, value):
        if value:
            # print(value, type(value), value.name, value.size)
            allowed_extensions = [str(allowed_extension).lower() for allowed_extension in self.extension]
            file_type = str(value.name).split('.')[-1].lower()

            if allowed_extensions and file_type not in allowed_extensions:
                raise CustomValidationError(detail='不允许当前文件类型')

            if self.max_upload_size and self.max_upload_size*1024*1024 < value.size:

                raise CustomValidationError(detail=f'当前文件太大，请保持在{self.max_upload_size}M以下')


class CharFieldSerializerValidator:
    """
    字符串字段验证
    length:长度验证
    field_text:提示字段名
    regular_list: 正则验证列表
    regular_help_text：正则验证错误提示文本列表

    正则验证中文表达式 r'[\u4e00-\u9fa5]'
    空格 r'\s'
    """
    def __init__(self, length=None, field_text=None, regular_list=None, regular_help_text=None):

        self.length = length
        self.field_text = field_text
        self.regular_list = regular_list if regular_list is not None else []
        self.regular_help_text = regular_help_text if regular_help_text is not None else []

    def __call__(self, value):
        if value:
            value = str(value)
            if self.length:
                if len(value) < self.length[0]:
                    raise CustomValidationError(detail=f'{self.field_text if self.field_text else ""}最小长度为{self.length[0]}')
                elif self.length[1] and len(value) > self.length[1]:
                    raise CustomValidationError(detail=f'{self.field_text if self.field_text else ""}最大长度为{self.length[1]}')

            if self.regular_list:
                for i in range(len(self.regular_list)):
                    if re.search(self.regular_list[i], value) is None:
                        msg = f'{self.field_text if self.field_text else ""}数据无效'
                        if self.regular_help_text:
                            msg = self.regular_help_text[min(i, len(self.regular_help_text)-1)]
                        raise CustomValidationError(detail=msg)










